package com.mina;

import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CompletableFuture;

/**
 * @author MH
 */
public class MINATest {
    private IoSession mIoSession;

    public static void main(String[] args) {
        try {
            MINATest test = new MINATest();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public MINATest() throws Exception {
        IoAcceptor acceptor = new NioSocketAcceptor();

        // 过滤链
        acceptor.getFilterChain().addLast("logger", new LoggingFilter());
        acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(StandardCharsets.UTF_8)));

        // 自定义handler
        SocketServerHandler socketServerHandler = new SocketServerHandler();
        acceptor.setHandler(socketServerHandler);

        // 服务器端绑定80端口，等待客户端连接请求。
        acceptor.bind(new InetSocketAddress(80));

        waitServerInput();
    }

    // Apache MINA的Socket服务器端。
    private class SocketServerHandler extends IoHandlerAdapter {

        public SocketServerHandler() {

        }

        // 会话创建。
        @Override
        public void sessionCreated(IoSession session) throws Exception {
            super.sessionCreated(session);
            // System.out.println("#sessionCreated#");
        }

        // 会话打开时触发（第一次连接打开时先触发sessionCreated，后触发本函数）。
        @Override
        public void sessionOpened(IoSession session) throws Exception {
            super.sessionOpened(session);
            // System.out.println("#sessionOpened#");

            mIoSession = session;
        }

        @Override
        public void messageSent(IoSession session, Object message) throws Exception {
            super.messageSent(session, message);
            // System.out.println("\n#messageSent#");
            // System.out.println(message.toString());
            // System.out.println("=============");
        }

        // 接收到消息时触发。
        @Override
        public void messageReceived(IoSession session, Object message) throws Exception {
            super.messageReceived(session, message);
            // System.out.println("messageReceived");

            System.out.println("客户端说:" + message.toString());
        }

        @Override
        public void sessionClosed(IoSession session) throws Exception {
            super.sessionClosed(session);
            System.out.println("\n#sessionClosed#");
            sessionInfoPrinter(session);
        }

        @Override
        public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
            super.sessionIdle(session, status);
            System.out.println("#sessionIdle#");
        }

        @Override
        public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
            super.exceptionCaught(session, cause);
            System.out.println("#exceptionCaught#");
            sessionInfoPrinter(session);
            cause.printStackTrace();
        }
    }

    private void sessionInfoPrinter(IoSession session) {
        StringBuffer sb = new StringBuffer();
        sb.append("\n" + session.toString());
        sb.append("\nId:" + session.getId());
        sb.append("\nLocalAddress:" + session.getLocalAddress());
        sb.append("\nRemoteAddress:" + session.getRemoteAddress());
        System.out.println(sb.toString());
    }

    // 开个线程  循环读  循环写
    private void waitServerInput() {
        CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

                String s = null;
                while (true) {
                    try {
                        // 读
                        s = br.readLine();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    try {
                        //写
                        mIoSession.write(s);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    if (s.equals("bye")) {
                        break;
                    }
                }

                try {
                    br.close();
                    mIoSession.closeOnFlush();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}